home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / maestro / source / timeline / select.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-15  |  24.9 KB  |  574 lines

  1. /*
  2.  * Copyright (c) 1990, 1991 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, and distribute this software and 
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that (i) the above copyright notices and this permission notice appear in
  7.  * all copies of the software and related documentation, and (ii) the name
  8.  * Stanford may not be used in any advertising or publicity relating to
  9.  * the software without the specific, prior written permission of
  10.  * Stanford.
  11.  * 
  12.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  13.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  14.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  15.  *
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  17.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES
  18.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT
  19.  * ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY,
  20.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21.  * SOFTWARE.
  22.  */
  23.  
  24. /* $Header: /Source/Media/collab/TimeLine/RCS/select.c,v 1.0 91/09/30 17:02:47 chua Exp Locker: drapeau $ */
  25. /* $Log:    select.c,v $
  26.  * Revision 1.0  91/09/30  17:02:47  chua
  27.  * Update to version 1.0
  28.  * 
  29.  * Revision 0.66  91/09/23  17:20:11  chua
  30.  * In DrawSelectArea, set areaSelected to 0 initially.  It will be set to 1
  31.  * if an area has been selected.
  32.  * 
  33.  * Revision 0.65  91/09/19  17:29:07  chua
  34.  * Make sure that variables are initialized properly.  Change formatting slightly,
  35.  * so that (if, for, while) statements with only one statement in them will not have
  36.  * braces.
  37.  * 
  38.  * Revision 0.64  91/09/16  15:13:33  chua
  39.  * In calls to InstrumentNew, add an extra parameter at the end. (Refer to the comments
  40.  * in instrument.c as to what this extra parameter represents).
  41.  * 
  42.  * Revision 0.63  91/09/04  15:13:51  chua
  43.  * Use AlertMessage whenever a notice_prompt is to be displayed.
  44.  * 
  45.  * Revision 0.62  91/07/26  17:28:43  chua
  46.  * In DrawSelectArea, update the start and end fields in the region info popup
  47.  * window.
  48.  * 
  49.  * Revision 0.61  91/07/17  10:38:20  chua
  50.  * In the DrawSelectArea procedure, while drawing the rectangle, take into account
  51.  * the actual time of the canvas starting position (tlFrame->canvasStart).
  52.  * 
  53.  * The definition of the playback head position, lastX has been changed.  It now
  54.  * indicates its position in terms of pixel value at the lowest zoom level.  So code
  55.  * where lastX or the DrawPlaybackHead function is called will have some changes.
  56.  * 
  57.  * Revision 0.60  91/07/09  18:25:07  chua
  58.  * Made changes to the startX, endX variables so that they now store the position at the
  59.  * largest zoom level (zoom level = 1).   Thus, the appropriate multiplication or
  60.  * division by the zoom level has to be made when these variables are used.  This will
  61.  * include lastX (position of the playback head) as well.
  62.  * 
  63.  * Revision 0.59  91/07/09  17:03:16  chua
  64.  * *** empty log message ***
  65.  * 
  66.  * Revision 0.58  91/06/25  17:48:01  chua
  67.  * Scale the positions of notes according to the zoom level, to cater for zooming.
  68.  * 
  69.  * Revision 0.57  91/06/05  16:23:43  chua
  70.  * Delete lines 245-250 in DeleteNotesFromList as we do not need to reset the 
  71.  * selectedInstrument pointer, since this will be done in the DeselectNote routine that
  72.  * will be called by the InitNotesInfo function.
  73.  * 
  74.  * Revision 0.56  91/06/04  17:37:27  chua
  75.  * Added the copyright comments in the beginning of the file.
  76.  * 
  77.  * Revision 0.55  91/06/04  17:31:15  chua
  78.  * Replace all occurrences of clipInstHead with TimeLineWindow[0]->instHead, since
  79.  * TimeLineWindow[0] is reserved for use as the clipboard.
  80.  * 
  81.  * Revision 0.54  91/06/04  10:43:57  chua
  82.  * Added a call to UpdateHeader to update the header of the frame whenever
  83.  * there is a change in the status of the change flag.
  84.  * 
  85.  * Revision 0.53  91/06/03  11:12:06  chua
  86.  * Make changes to accomodate multiple documents.  This involves identifying
  87.  * which is the current active window, that is, the one where the last mouse
  88.  * click was done.
  89.  * 
  90.  * Revision 0.52  91/05/30  12:09:55  chua
  91.  * Added an extra parameter (deselect) in the call to InitNotesInfo.
  92.  * 
  93.  * Revision 0.51  91/05/29  14:45:04  chua
  94.  * Remove the ClearNotesInfoList function calls as the InitNotesInfo procedure has been rewritten
  95.  * such that the ClearNotesInfoList function is no longer required.
  96.  * 
  97.  * Revision 0.50  91/05/24  16:37:58  chua
  98.  * 
  99.  * 
  100.  * Revision 0.49  91/05/23  17:39:13  chua
  101.  * *** empty log message ***
  102.  * 
  103.  * Revision 0.48  91/05/22  16:42:34  chua
  104.  * In the DeleteNotesFromList function (line 182), check for both areaSelected and noteSelected
  105.  * instead of just areaSelected.
  106.  * 
  107.  * Similar for lines 188 and line 319.
  108.  * 
  109.  * Revision 0.47  91/05/22  14:00:53  chua
  110.  * In the if-statements where if (... startX != endX) occurs, replace them with 
  111.  * if (... (areaSelected || noteSelected)).  This is a way of checking if either a note or a
  112.  * region is selected and eliminates errors found in the previous version.
  113.  * 
  114.  * Revision 0.46  91/05/22  11:51:12  chua
  115.  * If the PasteFromClipboard routine, 3rd line, instead of check if (areaSelected), check if
  116.  * startX != endX, which indicates that either an area or a note has been selected.  This
  117.  * allows us to paste over a selected area or a selected note.
  118.  * 
  119.  * Revision 0.45  91/05/17  16:58:58  chua
  120.  * *** empty log message ***
  121.  * 
  122.  * Revision 0.44  91/05/17  16:58:15  chua
  123.  * *** empty log message ***
  124.  * 
  125.  * Revision 0.43  91/05/17  16:57:24  chua
  126.  * *** empty log message ***
  127.  * 
  128.  * Revision 0.42  91/05/16  14:40:05  chua
  129.  * In the DeleteNotesFromList function, a check is made to see if we are deleting from a region
  130.  * or just a selected note.  If it is the latter, we need to set the infoNote pointer for that
  131.  * instrument to NULL, since the selected note is to be deleted, and the infoNote pointer will
  132.  * point to nothing then.
  133.  * 
  134.  * Revision 0.41  1991/05/15  02:48:51  chua
  135.  * Added a new function CheckClipboardInstPresent, which is called within
  136.  * the PasteFromClipboard function.
  137.  * This function will go through the clipboard instrument list and make sure that all the
  138.  * instruments on the clipboard are open and selected (if an area has been selected).
  139.  *
  140.  * An extra parameter is added to the DeleteNotesFromList function, refresh, which indicates
  141.  * if a canvas refresh is necessary after deletion.  The only time when it is not necessary
  142.  * is if it is called from the PasteFromClipboard function, since a pasting operation will
  143.  * follow the deletion and it is necessary only to refresh after the pasting has been done.
  144.  *
  145.  * In the PasteFromClipboard function, paste will now replace any selected area with the
  146.  * contents of the clipboard (provided the selected area contains all the instruments in the
  147.  * clipboard).  Also, if the insertion point falls in the middle of a note, the pasting of
  148.  * the clipboard contents for that instrument will occur only at the end of that note.
  149.  *
  150.  * Revision 0.40  1991/04/24  00:29:40  chua
  151.  * This file contains the functions that handle the selection routines.  The functions are:
  152.  * DrawSelectArea - makes sure that the start points are less than the end points and highlights the
  153.  *                  selected area on the screen.
  154.  * CopyToClipboard - copies the selected area onto the clipboard, which is essentially another instrument
  155.  *                   list resembling the TimeLine instrument list (described in instrument.c)
  156.  * DeleteNotesFromList - deletes the selected notes from the TimeLine.
  157.  * CreateDuplicateNoteList - Makes a duplicate note list from one that is in the clipboard.
  158.  * PasteFromClipboard - Inserts what is contained in the clipboard onto the TimeLine document, placed at
  159.  *             where the playback head is.
  160.  * */
  161.  
  162. static char selectrcsid[] = "$Header: /Source/Media/collab/TimeLine/RCS/select.c,v 1.0 91/09/30 17:02:47 chua Exp Locker: drapeau $";
  163.  
  164. #include "main.h"
  165.  
  166. int clipDuration;
  167. /*
  168.  * This function will first check the start and ending X and Y positions to make sure that the start is less than the end.
  169.  * It then draws the shaded rectangle indicating the area selected.
  170.  * Called by DrawCanvasEventHandler (canvas.c)
  171.  */
  172. void DrawSelectArea(tlFrame)
  173.      TimeLineFramePtr tlFrame;
  174. {
  175.   int temp;
  176.   
  177.   if (tlFrame->startX > tlFrame->endX)                    /* Make sure that startX is less than endX */
  178.   {
  179.     temp = tlFrame->startX;
  180.     tlFrame->startX = tlFrame->endX;
  181.     tlFrame->endX = temp;
  182.   }
  183.   if (tlFrame->startY > tlFrame->endY)                    /* Make sure that startY is less than endY */
  184.   {
  185.     temp = tlFrame->startY;
  186.     tlFrame->startY = tlFrame->endY;
  187.     tlFrame->endY = temp;
  188.   }
  189.   if (tlFrame->startX < 0)                        /* Make sure that startX is non-negative */
  190.     tlFrame->startX = 0;
  191.   SetStartEndRegion (tlFrame, tlFrame->startX, tlFrame->endX);
  192.   XFillRectangle(tlFrame->dpyDraw, tlFrame->xidDraw, tlFrame->gcLine, 
  193.          (tlFrame->startX / tlFrame->zoomLevel) - tlFrame->canvasStart,
  194.          tlFrame->startY, (tlFrame->endX - tlFrame->startX) / tlFrame->zoomLevel,
  195.          tlFrame->endY - tlFrame->startY);            /* Fill the selected rectangle */
  196.   tlFrame->areaSelected = 0;
  197.   if (tlFrame->startX != tlFrame->endX && 
  198.       tlFrame->startY != tlFrame->endY)                    /* Make sure that an area has really been selected */
  199.   {
  200.     tlFrame->areaSelected = 1;
  201.     tlFrame->noteSelected = 0;
  202.   }
  203. }
  204.  
  205. /* 
  206.  * This function checks the selected area and determines which notes belong in it and copies the selected area to the clipboard.  
  207.  * Partially selected notes are not included and are replaced by blank periods of time equivalent to the length of the partially selected portion 
  208.  * of the note.
  209.  * We have to create new instrument and new note nodes for the clipboard, rather than simply setting pointers to the selected instrument and notes.
  210.  * This is in case the original instruments are changed.  The clipboard would not be affected by operations such as loading in a new file etc,
  211.  * since it has its own allocated memory instead of just pointers.
  212.  * Called by CutHandler and CopyHandler (edit.c)
  213.  */
  214. void CopyToClipboard(tlFrame)
  215.      TimeLineFramePtr tlFrame;
  216. {
  217.   int         startApp, numApps;
  218.   int         i, finished;
  219.   Instrument     *origInst, *newInst;
  220.   Note         *newNote, *origNote;
  221.   
  222.   startApp = tlFrame->startY / (IconHeight + IconGap);            /* Determine which instruments are selected */
  223.   numApps = tlFrame->endY / (IconHeight + IconGap) - startApp;
  224.   if (numApps > 0 && 
  225.       (tlFrame->areaSelected || tlFrame->noteSelected))            /* Make sure that at least one instrument has been selected */
  226.   {
  227.     FreeInstrumentList(TimeLineWindow[0]);                /* Clear the old clipboard instrument list */
  228.     clipDuration = tlFrame->endX - tlFrame->startX;
  229.     origInst = (Instrument *) FindInstrument(startApp, tlFrame);    /* Get the first selected instrument */
  230.     TimeLineWindow[0]->numberOfApps = numApps;
  231.     for (i=0; i < numApps; i++) 
  232.     {
  233.       if (i == 0)                            /* Create new instruments for the clipboard */
  234.       {
  235.     TimeLineWindow[0]->instHead = (Instrument *) InstrumentNew(0, origInst->port, TimeLineWindow[0], NULL);
  236.     newInst = TimeLineWindow[0]->instHead;
  237.       }
  238.       else 
  239.       {
  240.     newInst->next = (Instrument *) InstrumentNew(i, origInst->port, TimeLineWindow[0], NULL);
  241.     newInst = newInst->next;
  242.       }
  243.       newInst->numnotes = 0;
  244.       origNote = origInst->firstNote;
  245.       finished = 0;
  246.       while (origNote != NULL && !finished)                /* Go through the notes list and copy those that are selected onto the clipboard */
  247.       {
  248.     if (origNote->start > tlFrame->endX)   /* Check if this note list is done */
  249.       finished = 1;
  250.     else if (origNote->start >= tlFrame->startX 
  251.          && origNote->end <= tlFrame->endX) /* Copy the note into the clipboard instrument list */
  252.     {
  253.       if (newInst->firstNote == NULL) 
  254.       {
  255.         newInst->firstNote = (Note *) malloc(sizeof(Note));
  256.         newNote = newInst->firstNote;
  257.       }
  258.       else 
  259.       {
  260.         newNote->next = (Note *) malloc(sizeof(Note));
  261.         newNote = newNote->next;
  262.       }
  263.       newInst->numnotes++;
  264.       newNote->start = origNote->start - tlFrame->startX;
  265.       newNote->end = origNote->end - tlFrame->startX;
  266.       newNote->ms = origNote->ms;
  267.       CalculateNoteTime(newNote);
  268.       newNote->next = NULL;
  269.     }
  270.     origNote = origNote->next;
  271.       }
  272.       origInst = origInst->next;
  273.     }
  274.   }
  275. }
  276.  
  277. /* 
  278.  * This function will delete the selected notes and/or time intervals from the instruments.  
  279.  * The parameter refresh indicates if the canvas is to be redrawn immediately after the notes are deleted.  This may not be necessary if this function
  280.  * is called from the paste routine, since we are going to paste notes right after the deletion and refreshing should only be done after the pasting.
  281.  * The variables tempstartX and tempendX are used to keep track of the actual starting and end X positions of the region to be deleted.  This is because
  282.  * partially selected notes are not deleted.  So if there are partially selected notes on both ends of the selected area, the area actually being deleted
  283.  * would be less than the selected area.
  284.  * Called by CutHandler and DeleteHandler (edit.c)
  285.  */
  286. void DeleteNotesFromList(refresh, tlFrame)
  287.      int refresh;
  288.      TimeLineFramePtr tlFrame;
  289. {
  290.   int         startApp, numApps;
  291.   int         i, finished;
  292.   int         tempstartX, tempendX;
  293.   int         numDeletedNotes;                    /* Keep track of number of notes deleted for an instrument */
  294.   Instrument     *currentInst;
  295.   Note         *prevNote, *currentNote;
  296.   
  297.   startApp = tlFrame->startY / (IconHeight + IconGap);            /* Determine which instruments are selected */
  298.   numApps = tlFrame->endY / (IconHeight + IconGap) - startApp;
  299.   if (numApps > 0 && (tlFrame->areaSelected || tlFrame->noteSelected)) /* Make sure that at least one instrument has been selected */
  300.   {
  301.     tlFrame->change = 1;                        /* Set the change flag on */
  302.     UpdateHeader(tlFrame, 1);
  303.     currentInst = (Instrument *) FindInstrument(startApp,
  304.                         tlFrame);        /* Find the first selected instrument in the selected area */
  305.     for (i=0; i < numApps; i++) 
  306.     {
  307.       tempstartX = tlFrame->startX;
  308.       tempendX = tlFrame->endX;
  309.       numDeletedNotes = 0;
  310.       currentNote = currentInst->firstNote;                /* Go through the notes list to determine which note falls in the selected area */
  311.       prevNote = currentNote;
  312.       finished = 0;
  313.       while (currentNote != NULL && !finished)
  314.       {
  315.     if (currentNote->start < tlFrame->startX && 
  316.         currentNote->end >= tlFrame->startX) /* Overlapping note in the beginning of the selected region */
  317.     {
  318.       tempstartX = currentNote->end;
  319.       prevNote = currentNote;
  320.       currentNote = currentNote->next;
  321.     }
  322.     else if (currentNote->start <= tlFrame->endX 
  323.          && currentNote->end > tlFrame->endX) 
  324.     {                                /* Overlapping note in the end of the selected region */
  325.       tempendX = currentNote->start;
  326.       finished = 1;
  327.     }
  328.     else if (currentNote->start > tlFrame->endX) /* No need to go on anymore as further notes are out of the selected region */
  329.       finished = 1;
  330.     else if (currentNote->start >= tlFrame->startX && 
  331.          currentNote->end <= tlFrame->endX) /* The whole note is in the selected region */
  332.     {
  333.       if (currentNote == currentInst->firstNote)            /* Check if the first note is to be deleted */
  334.       {
  335.         currentInst->firstNote = currentNote->next;
  336.         numDeletedNotes ++;
  337.         free (prevNote);
  338.         currentNote = currentInst->firstNote;
  339.         prevNote = currentNote;
  340.       }
  341.       else 
  342.       {
  343.         prevNote->next = currentNote->next;
  344.         numDeletedNotes ++;
  345.         free (currentNote);
  346.         currentNote = prevNote->next;
  347.       }
  348.     }
  349.     else 
  350.     {                                /* None of the above cases satisfied.  Go on to check the next note on the list */
  351.       prevNote = currentNote;
  352.       currentNote = currentNote->next;
  353.     }
  354.       }
  355.       while (currentNote != NULL)                    /* Update the start and end positions of the notes following the selected region */
  356.       {                                    /* Since an area has been deleted, the start and end points of the notes following */
  357.     currentNote->start -= (tempendX - tempstartX);            /* the deleted area needs to be changed. */
  358.     currentNote->end -= (tempendX - tempstartX);
  359.     CalculateNoteTime(currentNote);
  360.     currentNote = currentNote->next;
  361.       }
  362.       currentInst->numnotes -= numDeletedNotes;
  363.       currentInst->infoNote = NULL;
  364.       InitNotesInfo(currentInst, 1, tlFrame);
  365.       currentInst = currentInst->next;
  366.     }
  367.     tlFrame->noteSelected = 0;
  368.     tlFrame->areaSelected = 0;
  369.     SetStartEndRegion(tlFrame, 0, 0);
  370.     if (refresh == 1) 
  371.       DrawCanvasRepaintHandler(tlFrame->TimeLine_window->DrawCanvas, tlFrame->paintWinDraw, 
  372.                    tlFrame->dpyDraw, tlFrame->xidDraw, NULL); /* Redraw the canvas with the new changes */
  373.   }
  374. }
  375.  
  376. /* 
  377.  * This function will take a clipboard note list and forms a duplicate copy of it for insertion onto the timeline.
  378.  * Called by PasteFromClipboard (select.c)
  379.  */
  380. Note *CreateDuplicateNoteList(noteHeader, insertPoint) 
  381.      Note *noteHeader;
  382.      long insertPoint;
  383. {
  384.   Note *newNoteList, *origNote, *newNote;
  385.   
  386.   if (noteHeader == NULL)                        /* Take no action if the note list is empty */
  387.     return NULL;
  388.   newNoteList = (Note *) malloc(sizeof(Note));                /* Create a new note list */
  389.   newNote = newNoteList;
  390.   origNote = noteHeader;
  391.   while (origNote != NULL)                        /* Go through the clipboard note list and duplicate the whole list */
  392.   {
  393.     newNote->start = origNote->start + insertPoint;
  394.     newNote->end = origNote->end + insertPoint;
  395.     newNote->ms = origNote->ms;
  396.     CalculateNoteTime(newNote);
  397.     if (origNote->next != NULL) 
  398.       newNote->next = (Note *) malloc(sizeof(Note));
  399.     else 
  400.       newNote->next = NULL;
  401.     newNote = newNote->next;
  402.     origNote = origNote->next;
  403.   }
  404.   return (newNoteList);
  405. }
  406.  
  407. /*
  408.  * This function checks if each instrument in the clipboard is currently open on the timeline.  If an area has been selected, the function
  409.  * also checks to make sure that the instrument is selected.
  410.  * If any of the instruments are not open or selected, a notice message notifying the user which instrument is not open/selected is displayed,
  411.  * and an error message is returned to the calling function.
  412.  * Called by PasteFromClipboard (select.c)
  413.  */
  414. int CheckClipboardInstPresent(tlFrame)  
  415.      TimeLineFramePtr tlFrame;
  416. {
  417.   Instrument     *clipInstrument, *instrument;
  418.   char         buf[70], buf1[70], buf2[70];
  419.   int         found;
  420.   
  421.   clipInstrument = TimeLineWindow[0]->instHead;
  422.   while (clipInstrument != NULL) 
  423.   {
  424.     instrument = tlFrame->instHead;                    /* Find the corresponding instrument on the timeline */
  425.     found = 0;
  426.     while (instrument != NULL && !found) 
  427.     {
  428.       if (strcmp(instrument->port->appName, clipInstrument->port->appName) == 0)
  429.       {
  430.     if (tlFrame->areaSelected || tlFrame->noteSelected)        /* If an area has been selected, check that the instrument is selected. */
  431.     {
  432.       if (instrument->relativePosition >= tlFrame->startY / (IconHeight + IconGap) &&
  433.           instrument->relativePosition < tlFrame->endY / (IconHeight + IconGap)) 
  434.         found = 1;
  435.       else                                /* If instrument is not in selected area, do not paste */
  436.         instrument = NULL;
  437.     }
  438.     else 
  439.       found = 1;
  440.       }
  441.       else 
  442.     instrument = instrument->next;
  443.     }
  444.     if (!found)                            /* At least one of the required applications is not open. */
  445.     {
  446.       sprintf (buf, "Sorry, the application %s is not open or selected.", clipInstrument->port->appName);
  447.       sprintf (buf1, "Pasting from the clipboard cannot be done unless all the");
  448.       sprintf (buf2, "applications in the clipboard are open and selected (if applicable).");
  449.       AlertMessage(tlFrame, buf, buf1, buf2);
  450.       return (Error);
  451.     }
  452.     clipInstrument = clipInstrument->next;
  453.   }
  454.   return (OK);
  455. }
  456.  
  457. /* 
  458.  * This function will paste the contents of the clipboard onto the current timeline document, starting from where the playback head is.
  459.  * First, a check is made (by calling the function CheckClipboardInstPresent) to make sure that all the instruments in the clipboard are open
  460.  * and are in the selected area (if an area has been selected).
  461.  * If an area has been selected and the above check is ok, the notes in the selected area are deleted.  However, no refreshing of the canvas is
  462.  * done yet, since pasting is to be done next.  The playback head will be redrawn to the starting position of the selected area.
  463.  * If a playback head position is defined, the function will proceed to do the pasting operation.
  464.  * It will find the matching instrument on the current timeline instrument list for each instrument in the clipboard instrument list.
  465.  * It then goes through the timeline instrument notes list to determine where the insertion should be made.
  466.  * Next, it will make a duplicate copy of the clipboard instrument notes list by calling the function CreateDuplicateNoteList (above).
  467.  * The insertion of the duplicate clipboard instrument notes list is then made and the start and end positions of the original notes in the
  468.  * timeline instrument notes list following the insertion point is updated.
  469.  * The pop-up info window is then updated, and the changes displayed on the canvas by calling the Draw Canvas repaint handler.
  470.  *
  471.  * Note that if the insertion point falls in the middle of a note, the clipboard section for that instrument will only be pasted after the end of that
  472.  * note.  This may result in the pasted sections of different instruments starting at different insertion points.
  473.  *
  474.  * Called by PasteHandler (edit.c)
  475.  */
  476. void PasteFromClipboard(tlFrame)
  477.      TimeLineFramePtr tlFrame;
  478. {
  479.   Instrument     *clipInstrument, *instrument;
  480.   int found;
  481.   long         insertPoint;
  482.   Note         *prevNote, *currentNote, *nextNote, *newNoteList;
  483.  
  484.   if (CheckClipboardInstPresent(tlFrame) == OK)                /* Check if all instruments in the clipboard are open or selected. */
  485.   {
  486.     if (tlFrame->areaSelected || tlFrame->noteSelected)            /* Check if either a note or an area is selected */
  487.     {
  488.       DeleteNotesFromList(0, tlFrame);
  489.       DrawPlaybackHead(tlFrame->startX, tlFrame);
  490.     }
  491.   }
  492.   else 
  493.     return;                                /* No need to continue processing as at least one instrument is not open/selected */
  494.   if (tlFrame->lastX >= 0)                        /* Check that the playback head has been positioned somewhere on the timeline */
  495.   {
  496.     clipInstrument = TimeLineWindow[0]->instHead;
  497.     while (clipInstrument != NULL) 
  498.     {
  499.       instrument = tlFrame->instHead;                    /* Find the corresponding instrument on the timeline */
  500.       found = 0;
  501.       insertPoint = tlFrame->lastX;                    /* Set the initial insertion point to be where the playback head is */
  502.       while (instrument != NULL && !found)                /* Now, an instrument is guaranteed to be found, since a check was made earlier */
  503.       {
  504.     if (strcmp(instrument->port->appName, clipInstrument->port->appName) == 0)
  505.       found = 1;
  506.     else 
  507.       instrument = instrument->next;
  508.       }
  509.       if (instrument->firstNote == NULL)                /* No notes currently in the instrument where the paste is to occur */
  510.       {
  511.     newNoteList = CreateDuplicateNoteList(clipInstrument->firstNote, 
  512.                           insertPoint);        /* Get a duplicate copy of the clipboard instrument note list */
  513.     instrument->firstNote = newNoteList;
  514.       }
  515.       else 
  516.       {
  517.     currentNote = instrument->firstNote;                /* Go through the instrument note list to determine at which point in the */
  518.     prevNote = currentNote;                        /* note list should the paste occur. */
  519.     found = 0;
  520.     while (currentNote != NULL && !found) 
  521.     {
  522.       if (currentNote->start >= insertPoint)
  523.         found = 1;
  524.       else 
  525.       {
  526.         prevNote = currentNote;
  527.         currentNote = currentNote->next;
  528.       }
  529.     }
  530.     if (currentNote == instrument->firstNote)            /* Paste before all the notes in the current note list */
  531.     {
  532.       nextNote = instrument->firstNote;
  533.       newNoteList = CreateDuplicateNoteList(clipInstrument->firstNote, 
  534.                         insertPoint);        /* Get a duplicate copy of the clipboard instrument note list */
  535.       if (newNoteList != NULL) 
  536.         instrument->firstNote = newNoteList;
  537.     }
  538.     else 
  539.     {                                /* Set the previous note before the playback head to point to the */
  540.       if (prevNote->end > insertPoint)                /* If the insert point falls in the middle of a note, insert after the note */
  541.         insertPoint = prevNote->end;
  542.       newNoteList = CreateDuplicateNoteList(clipInstrument->firstNote, 
  543.                         insertPoint);        /* Get a duplicate copy of the clipboard instrument note list */
  544.       nextNote = prevNote->next;                    /* duplicated clipboard note list */
  545.       if (newNoteList != NULL) 
  546.         prevNote->next = newNoteList;
  547.     }
  548.     if (newNoteList != NULL)                    /* Set the end of the duplicated clipboard note list to point to the next */
  549.     {                                /* note after the playback head position */
  550.       currentNote = newNoteList;
  551.       while (currentNote->next != NULL) 
  552.         currentNote = currentNote->next;
  553.       currentNote->next = nextNote;
  554.     }
  555.     while (nextNote != NULL)                    /* Update the start and end positions of the notes following the selected region */
  556.     {
  557.       nextNote->start += clipDuration;
  558.       nextNote->end += clipDuration;
  559.       CalculateNoteTime(nextNote);
  560.       nextNote = nextNote->next;
  561.     }
  562.       }
  563.       instrument->numnotes += clipInstrument->numnotes;
  564.       InitNotesInfo(instrument, 1, tlFrame);                /* Update the info pop-up window */
  565.       clipInstrument = clipInstrument->next;
  566.     }
  567.     tlFrame->change = 1;                        /* Set the change flag on */
  568.     UpdateHeader(tlFrame, 1);
  569.     DrawCanvasRepaintHandler(tlFrame->TimeLine_window->DrawCanvas, tlFrame->paintWinDraw, 
  570.                  tlFrame->dpyDraw, tlFrame->xidDraw, NULL);
  571.   }
  572. }
  573.  
  574.